import numpy as np 
from sklearn.svm import SVR
from sklearn.preprocessing import StandardScaler
import Read_data
from math import sqrt
import PCAprocess
import matplotlib.pyplot as plt
from sklearn.metrics import r2_score, mean_squared_error, mean_absolute_error
import write_data

'''
SVR处理模块
输入：特征集（list），标签（list），训练集比例（float）,svr核函数（字符串）
输出：测试集预测数据（list），图像，评估指标
'''
class SVRProcess:
    def __init__(self, feature, label, placename, train_ratio=0.5, kernel='linear'):
        #数据成员
        self.feature = feature
        self.label = label
        self.train_ratio=train_ratio
        self.placename=placename
        self.x_train=[]
        self.y_train=[]
        self.x_test=[]
        self.y_test=[]
        self.y_hat_real=[]
        self.y_test_real=[]
        self.kernel=kernel
        #方法
        self.mainProcess()

    #main函数
    def mainProcess(self):
        SVR_data=np.hstack((self.feature,self.label))
        self.data_classify(SVR_data)
        self.svrPredict()
        # print(self.y_hat_real)
        self.plot_svr()
        self.estimate_svr()



    #数据集分类
    def data_classify(self,SVR_data):
        n=len(SVR_data) #数据的行数
        len_train=int(self.train_ratio*(n+1))  #向下取整，训练集长度
        len_test=n-len_train #测试集长度

        train = SVR_data[:len_train,:]
        test = SVR_data[len_train:,:]

        #拆分输入和输出变量
        self.x_train = train[:,:-1]
        self.y_train = train[:,-1]
        print('训练集长度：'+str(len(self.y_train)))
        self.x_test = test[:,:-1]
        self.y_test = test[:,-1]
        self.y_test_real=self.y_test
        print('测试集长度：'+str(len(self.y_test)))
        


    #SVR预测
    def svrPredict(self):
        #训练数据和测试数据进行标准化处理
        ss_x = StandardScaler()
        x_train = ss_x.fit_transform(self.x_train)
        x_test = ss_x.transform(self.x_test)

        ss_y = StandardScaler()
        y_train = ss_y.fit_transform(self.y_train.reshape(-1, 1))
        y_test = ss_y.transform(self.y_test.reshape(-1, 1))

        #svr训练预测
        svr_model = SVR(kernel=self.kernel)
        svr_model.fit(x_train, y_train)
        y_hat = svr_model.predict(x_test)
        self.y_hat_real = ss_y.inverse_transform(y_hat) #预测值
        print("对线性核函数的默认评估值为：", svr_model.score(x_test, y_test))

    """
    获取绘图数据函数
    输入：两个一维list要按列并列写入文件，一个文件名
    输出：一个xls文件
    """
    def plotData(self,list1,list2,filename):
        plot_list1=np.array(list1).reshape((-1,1))
        plot_list2=np.array(list2).reshape((-1,1))
        plot_data=np.hstack((plot_list1,plot_list2))
        write_data.write_data(filename,plot_data)

    #画图
    def plot_svr(self):
        r = len(self.y_test_real) + 1
        
        #写出绘图数据
        self.plotData(self.y_hat_real,self.y_test_real,'PredictionResult/'+self.placename+'SVR_预测客流_真实客流_绘图数据.xls')

        plt.figure(figsize=(20,16)) #创建画布。大小为10*10，像素为160
        plt.style.use('dark_background') #黑色背景
        plt.title('组合模型预测客流与真实客流对比图') #添加标题
        plt.ylabel('客流量') #添加y坐标
        plt.plot(np.arange(1,r), self.y_hat_real, 'r-', label="预测客流")
        plt.plot(np.arange(1,r), self.y_test_real, '-', label="真实客流")
        plt.rcParams['lines.linewidth']=2 #修改线条宽度
        plt.rcParams['axes.spines.top']=False #去除顶部轴
        plt.rcParams['axes.spines.right']=False #去除右侧轴
        plt.rcParams['font.size']=26 # 设置字体大小
        
        plt.legend(loc='upper right')
        plt.savefig('PredictionResult/'+self.placename+'真实客流与预测客流对比折线图（SVR模型）.png')
        plt.show()

    #评估指标
    def estimate_svr(self):
        # 对线性核函数模型评估
        print("SVR决定系数(r方，R_squared)值为：", r2_score(self.y_test_real,self.y_hat_real))
        # 计算RMSE
        rmse = sqrt(mean_squared_error(self.y_test_real, self.y_hat_real))
        print('SVR均方根误差(RMSE,Root Mean Square Error): ',rmse)
        print("SVR均方误差(MSE, mean squared error)为:", mean_squared_error(self.y_test_real,self.y_hat_real))
        print("SVR平均绝对值误差(MAE,mean_absolute_error)为:", mean_absolute_error(self.y_test_real,self.y_hat_real))

# #联调测试
# rd_feature=Read_data.Read_data("data_siguniangshan.xlsx",1,13)#取第1列到第12列数据(list)
# feature_data1=rd_feature.outputdata

# pcaP=PCAprocess.PCAprocess(feature_data1,3)#PCA处理数据
# feature_data1=pcaP.output_data

# rd_feature2=Read_data.Read_data("data_siguniangshan.xlsx",14,22)#取第14列到第22列数据(list)
# feature_data2=rd_feature2.outputdata

# feature_data =np.hstack((feature_data1,feature_data2))#合并特征集

# rd_label=Read_data.Read_data("data_siguniangshan.xlsx",23,23)#取第23列数据客流
# label_data=rd_label.outputdata
# SVRProcess(feature_data,label_data,0.5,'linear')#svr处理数据